import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Map;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.events.ServerMessageEvent;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.event.listeners.ServerMessageListener;
import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Constants;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSItem;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class CraftingMiner extends Script implements ServerMessageListener,
		PaintListener {
	private final long startTime = System.currentTimeMillis();
	private int[] rocks;
	private final int[] picks = { 1265, 1267, 1269, 1273, 1271, 1275 };
	private final RSTile[] path = new RSTile[] { new RSTile(3013, 3357),
			new RSTile(3008, 3345), new RSTile(3008, 3331),
			new RSTile(3005, 3318), new RSTile(2992, 3309),
			new RSTile(2979, 3303), new RSTile(2962, 3302),
			new RSTile(2947, 3302), new RSTile(2934, 3299),
			new RSTile(2933, 3291) };
	private final RSTile mine = new RSTile(2940, 3284);
	private RSTile currentTile;
	final RSTile door = new RSTile(2933, 3289);
	private final int wait1 = 100, wait2 = 300, bankID = 11758;
	private boolean isMining = false;
	private int type, currentRock, mined, loads;
	private String doing = "Starting";

	private boolean canReachCustom(final RSTile... tile) {
		for (final RSTile t : tile) {
			if (canReach(t, true)) {
				return true;
			}
		}
		return false;
	}

	private Point checkPoint(final Point click) {
		int x = 0, y = 0, count = 0;
		while (count < 5) {
			moveMouse(click.x + x, click.y + y);
			wait(random(1000, 1200));
			if (getMenuItems().contains("Open Guild Door")) {
				return new Point(click.x + x, click.y + y);
			} else {
				String temp = "";
				for (final Object option : getMenuItems().toArray()) {
					temp += option + "|";
				}
				if (getMenuItems().contains("Open Guild Door")) {
					return new Point(click.x + x, click.y + y);
				}
			}
			switch (count) {
			case 0:
				x = 10;
				break;
			case 1:
				x *= -1;
				break;
			case 2:
				y = 10;
				x = 0;
				break;
			case 3:
				y *= -1;
				break;
			}
			count++;
		}
		return null;
	}

	@Override
	public String getAuthor() {
		return "Fusion89k";
	}

	@Override
	public String getName() {
		return "Crafting Guild Miner";
	}

	@Override
	public String getScriptCategory() {
		return "Mining";
	}

	@Override
	public String getScriptDescription() {
		return "<html>\n"
				+ "<head></head>\n"
				+ "<body>\n"
				+ "<center>"
				+ "<h2>"
				+ getName()
				+ "</h2>"
				+ "</center>\n"
				+ "<b>Author:</b> "
				+ getAuthor()
				+ "<br />"
				+ "<b>Version:</b> "
				+ getVersion()
				+ "<br><br>"
				+ "<form><input type=\"radio\" name=\"ore\" value=\"1\" checked=\"checked\">Gold <br><input type=\"radio\" name=\"ore\" value=\"2\"> Silver <br><input type=\"radio\" name=\"ore\" value=\"3\"> Clay</form><br>"
				+ "</body>\n" + "</html>";
	}

	@Override
	public double getVersion() {
		return 1.2;
	}

	private boolean isCarryingOneOfItem(final int... id) {
		// for (int i : id) {
		// if (equipmentContains(i) || inventoryContains(i))
		// return true;
		// }
		// return false;
		final RSItem[] items = getInventoryItems();
		for (final RSItem it : items) {
			if (it == null) {
				continue;
			}
			for (final int pick : picks) {
				if (it.getID() == pick) {
					return true;
				}
			}
		}
		return false;
	}

	private RSTile locate() {
		RSTile min = path[0];
		for (int i = 1; i < path.length; i++) {
			if (distanceTo(path[i]) < distanceTo(min)) {
				min = path[i];
			}
		}
		return min;
	}

	@Override
	public int loop() {
		setCameraAltitude(true);
		if (getMyPlayer().isMoving()) {
			return random(wait1, wait2);
		}
		if (!isInventoryFull()) {// Mining
			if (isMining) {
				try {
					if (getMyPlayer().getAnimation() == -1) {
						isMining = false;
						return random(wait1, wait2);
					}
					final int curID = getObjectAt(currentTile).getID();
					if (curID != currentRock) {
						doing = "Found Smoking Rock";
						isMining = false;
						mine();
					}
				} catch (final Exception e) {
					log("Smoking detection error - Do not post about this");
				}
				return random(wait1, wait2);
			}
			if (distanceTo(path[path.length - 1]) > 4 && !canReach(mine, true)) {
				doing = "Walking to Guild";
				walk(false);
				return random(wait1, wait2);
			}
			if (!canReach(mine, true)) {
				doing = "Opening Door";
				setCompass('n');
				if (!tileOnScreen(door)) {
					walkTileMM(door);
					wait(random(wait1, wait2));
				}
				openDoor();
				return random(wait1, wait2);
			}
			final RSObject rock = findObject(rocks);
			if (rock == null) {
				doing = "Waiting for Rock";
				randomStuff();
				return random(wait1, wait2);
			}
			if (distanceTo(rock) > 4) {
				doing = "Walking to Rocks";
				walkTileMM(rock.getLocation());
				return random(wait1, wait2);
			}
			mine();
			return random(wait1, wait2);
		} else {// Banking
			if (!canReachCustom(path)) {
				doing = "Opening Door";
				if (!tileOnScreen(door)) {
					walkTileMM(door);
					return random(wait1, wait2);
				}
				openDoor();
				return random(wait1, wait2);
			} else if (distanceTo(path[0]) > 4) {
				doing = "Walking to Bank";
				walk(true);
				return random(wait1, wait2);
			}
			if (!bank.getInterface().isValid()) {
				doing = "Finding Bank";
				final RSObject booth = findObject(bankID);
				if (booth == null) {
					return random(wait1, wait2);
				}
				if (distanceTo(booth.getLocation()) > 4) {
					walk(true);
					return random(wait1, wait2);
				}
				atObject(booth, "Use-Quickly");
				return random(wait1, wait2);
			} else {
				doing = "Depositing";
				loads++;
				bank.depositAllExcept(picks);
				bank.close();
				return random(wait1, wait2);
			}
		}
	}

	private void mine() {
		if (!isCarryingOneOfItem(picks)) {

			log("No Equipment");
			stopAllScripts();
		}
		final RSObject rock = findObject(rocks);
		if (rock == null) {
			walkTileMM(randomTile(getMyPlayer().getLocation()));
			isMining = false;
			return;
		}
		if (!tileOnScreen(rock.getLocation())) {
			rotate();
			mine();
		}
		doing = "Mining Rock";
		atObject(rock, "Mine");
		isMining = true;
		currentTile = rock.getLocation();
		currentRock = rock.getID();
		openTab(Constants.TAB_INVENTORY);
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
	}

	public void onRepaint(final Graphics g) {
		if (isLoggedIn()) {
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			final int topX = 515 - 173, topY = 337 - 80, x = topX + 5;
			int y = topY + 5;
			g.setColor(new Color(0, 100, 0, 100));
			g.fill3DRect(topX, topY, 515 - topX, 337 - topY, true);
			g.setColor(Color.green);
			g.drawString("Runtime: " + hours + "h " + minutes + "min "
					+ seconds + "sec.", x, y += 15);
			g.drawString("Ore Mined: " + Integer.toString(mined), x, y += 15);
			g.drawString("Loads Done: " + loads, x, y += 15);
			g.drawString("Status: " + doing, x, y += 15);
		}
	}

	@Override
	public boolean onStart(final Map<String, String> args) {
		type = Integer.parseInt(args.get("ore"));
		switch (type) {
		case 1:
			rocks = new int[] { 11183, 11184, 11185 };
			break;
		case 2:
			rocks = new int[] { 11186, 11187, 11188 };
			break;
		case 3:
			rocks = new int[] { 11189, 11190, 11191 };
			break;
		}
		return true;
	}

	private void openDoor() {
		Point click = Calculations.tileToScreen(door);
		click = checkPoint(click);
		if (click != null) {
			clickMouse(click, false);
			atMenu("Open");
			return;
		}
		turnToTile(door, 10);
		atDoor(getObjectAt(door), "north", "Open");
	}

	private void randomStuff() {
		final int temp = random(1, 100);
		switch (temp) {
		case 3:
		case 4:
			moveMouse(random(150, 450), random(100, 300));
			break;
		case 2:
			openTab(Constants.TAB_STATS);
			final RSTile mining = randomTile(new RSTile(680, 230));
			moveMouse(mining.getX(), mining.getY());
			break;
		case 6:
			openTab(random(0, 13));
			break;
		}
	}

	private RSTile randomTile(final RSTile location) {
		return randomTile(location, 2);
	}

	private RSTile randomTile(final RSTile location, final int diff) {
		final int x = location.getX(), y = location.getY();
		return new RSTile(random(x - diff, x + diff),
				random(y - diff, y + diff));
	}

	private void rotate() {
		setCameraRotation(getCameraAngle() + random(20, 90));
	}

	public void serverMessageRecieved(final ServerMessageEvent e) {
		final String word = e.getMessage().toLowerCase();
		if (word.contains("manage")) {
			mined++;
			isMining = false;
		}
	}

	private void walk(final boolean toBank) {
		if (getEnergy() > random(60, 100)) {
			setRun(true);
		}
		final RSTile start = locate();
		int loc = 0;
		for (int i = 0; i < path.length; i++) {
			if (start.equals(path[i])) {
				loc = i;
				break;
			}
		}
		if (toBank) {
			if (loc == 0) {
				walkTileMM(randomTile(path[0]));
				return;
			}
			walkTileMM(randomTile(path[loc - 1]));
		} else {
			if (loc == path.length - 1) {
				walkTileMM(randomTile(path[path.length - 1], 1));
				return;
			}
			walkTileMM(randomTile(path[loc + 1]));
		}
	}
}
